//*********************************************************************
// Copyright (C) 2014 Hell Prototypes / www.hellprototypes.com
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
//********************************************************************
#include <avr/io.h>
#include "common.h"

void ui_listmenu(const UI_listmenu_t *p_listmenu)
{
	uint8_t selected_item=0, disp_index=0, disp_line;

	while(1) {
		if(selected_item < 7){//if(selected_item == 0) {
			draw_string(p_listmenu->item_title, true, 1, 0);
			disp_line = 1;
			disp_index = 0;
		} else {
			disp_line = 0;
			disp_index = selected_item - 7;
		}

		for( ; disp_line<8; disp_line++) {
			if(p_listmenu->p_items[disp_index].item_content != NULL) {
				draw_string(p_listmenu->p_items[disp_index].item_content, 
								(disp_index == selected_item) ? true : false, 1, disp_line*8);
				disp_index++;
			} else {
				break;
			}
		}
		draw_end();
		switch( get_key_value(0) ) {
		case LISTMENU_CONFIRM:
			if(p_listmenu->p_items[selected_item].item_handle != NULL) {
				p_listmenu ->p_items[selected_item].item_handle();
			}
			break;
		case LISTMENU_UP:
			if(selected_item > 0) {
				selected_item--;
			}
			break;
		case LISTMENU_DOWN:
			if(selected_item < p_listmenu->items_num-2) {
				selected_item++;
			}
			break;
		case LISTMENU_CANCLE:
			return;
			break;
		}
	}
}

void ui_hex_editor(uint32_t start, uint32_t length, memory_callback_f mem_read_f)
{
	char str[25], ascii[9];
	uint8_t V, y, str_i, ascii_i, curr_line=0;
	uint16_t H;
	uint32_t base = start, page_base = start;
	bool end;

	while(1) {
		base = page_base;
		end = false;
		sprintf(str, "%02x", (uint8_t)((base>>16)&0xff));
		strupr(str);
		draw_string(str, true, 1, 0);//address:bit23:bit16

		sprintf(str, ">%u%%", (uint16_t)(((base+curr_line*HEX_EDITOR_LINE_SIZE)-start)*100/length));//place
		draw_string(str, false, 26, 0);
		
		for(V=0; (V<7) && (!end) && (base < (start + length)); V++) {
			sprintf(str, "%04x", (uint16_t)(base&0xffff));
			y = (V+1)*8;
			strupr(str);
			draw_string(str, true, 1, y);
			ascii_i = 0;
			str[0] = ':';
			str[1] = '\0';
			draw_string(str, false, 26, y);
			str_i = 0;
			for(H=0; H<8; H++) {
				uint32_t offset = H + base;
				if(offset >= (start + length)) {
					end = true;
					break;
				}
				uint8_t raw = mem_read_f(offset);
				if(V == curr_line) {
					char c;
					if((raw < ' ') || (raw > '~')) {
						c = '?';
					} else{
						c = (char)raw;
					}
					ascii[ascii_i++] = c;
				}
				sprintf(&str[str_i], "%02x", raw);
				str_i += 2;
			}
			base += H;
			if(V == curr_line) {
				ascii[ascii_i] = '\0';
				draw_string(ascii, true, 80, 0);
			}
			strupr(str);
			draw_string(str, (V == curr_line), 31, y);
		}
		draw_end();
		switch( get_key_value(0) ) {
		case HEX_EDITOR_CONFIRM:
			if(length > HEX_EDITOR_BLOCK_SIZE){
				if(page_base <= (start + length - HEX_EDITOR_BLOCK_SIZE)) {
					page_base += HEX_EDITOR_BLOCK_SIZE;
				} else {
					page_base = start;
				}
				curr_line = 0;
			} else {
				page_base = start;
			}
			break;
		case HEX_EDITOR_PAGE_UP:
			if(page_base >= (start + HEX_EDITOR_PAGE_SIZE)) {
				page_base -= HEX_EDITOR_PAGE_SIZE;
			} else {
				page_base = start;
			}
			curr_line = 0;
			break;
		case HEX_EDITOR_PAGE_DOWN:
			if(page_base <= (start + length - HEX_EDITOR_PAGE_SIZE)) {
				page_base += HEX_EDITOR_PAGE_SIZE;
			}
			curr_line = 0;
			break;
		case HEX_EDITOR_LINE_UP:
			if(curr_line > 0) {
				curr_line--;
			} else {
				if(page_base >= (start + HEX_EDITOR_LINE_SIZE)) {
					page_base -= HEX_EDITOR_LINE_SIZE;
				}
			}
			break;
		case HEX_EDITOR_LINE_DOWN:
			if(curr_line < V-1) {
				curr_line++;
			} else {
				if(page_base <= (start + length - HEX_EDITOR_PAGE_SIZE-HEX_EDITOR_LINE_SIZE)) {
					page_base += HEX_EDITOR_LINE_SIZE;
				}
			}
			break;
		case HEX_EDITOR_SECTION_UP:
			if(length > HEX_EDITOR_SECTION_SIZE){
				if(page_base >= (start + HEX_EDITOR_SECTION_SIZE)) {
					page_base -= HEX_EDITOR_SECTION_SIZE;
				} else {
					page_base = start;
				}
				curr_line = 0;
			}
			break;
		case HEX_EDITOR_SECTION_DOWN:
			if(length > HEX_EDITOR_SECTION_SIZE){
				if(page_base <= (start + length - HEX_EDITOR_SECTION_SIZE)) {
					page_base += HEX_EDITOR_SECTION_SIZE;
				}
				curr_line = 0;
			}
			break;
		case HEX_EDITOR_EXIT:
			return;
			break;
		}
	}
}

